﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ESB.Adapter;
using Microsoft.Practices.ESB.Exception.Management;
using Microsoft.Practices.ESB.Itinerary;
using Microsoft.Practices.ESB.Itinerary.Services;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Message.Interop;
using System.Reflection;

namespace BizTalk.ESB.Extensions.MessagingServices
{
    public class FileNameService : IMessagingService
    {
        public IBaseMessage Execute(IPipelineContext context, IBaseMessage msg, string resolverString, IItineraryStep step)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (msg == null)
                throw new ArgumentNullException("msg");
            if (string.IsNullOrEmpty(resolverString))
                throw new ArgumentException("Resolver must be provided", "resolverString");
            try
            {
                StringBuilder sbFileName = new StringBuilder(step.ResolverCollection.Count);

                // Build File Name from Action property of each Resolver Dictionary
                foreach (String resolver in step.ResolverCollection)
                {
                    EventLogger.Write("Current resolver string = " + resolver);
                    ResolverInfo info = ResolverMgr.GetResolverInfo(ResolutionType.Endpoint, resolver);
                    if (!info.Success)
                        throw new RoutingException("Invalid Resolver", resolverString);

                    // Get dictionary from resolver and validate
                    Dictionary<string, string> resolverDictionary = ResolverMgr.Resolve(info, msg, context);
                    if (string.IsNullOrEmpty(resolverDictionary["Resolver.Action"]))
                    {
                        throw new RoutingException("Action not provided in Resolver", resolverString);
                    }

                    sbFileName.Append(ParseAction(resolverDictionary["Resolver.Action"]));
                }

                // Save original File Name value
                msg.Context.Promote("OriginalFileName", @"https://BizTalk.Core.EsbExtensions.Itinerary.PropertySchemas.FileNameServiceProperties"
                    , msg.Context.Read("ReceivedFileName", @"http://schemas.microsoft.com/BizTalk/2003/file-properties"));

                // Set FILE.ReceivedFileName to enable %SourceFileName% macro functionality
                msg.Context.Promote("ReceivedFileName", @"http://schemas.microsoft.com/BizTalk/2003/file-properties"
                    , sbFileName.ToString());

                return msg;
            }
            catch (System.Exception ex)
            {
                EventLogger.Write(MethodInfo.GetCurrentMethod(), ex);
                throw;
            }   
        }

        public string Name
        {
            get { return "BizTalk.Core.Itinerary.MessagingServices.FileNameService"; }
        }

        public bool ShouldAdvanceStep(IItineraryStep step, IBaseMessage msg)
        {
            return true;
        }

        public bool SupportsDisassemble
        {
            get { return false; }
        }

        private String ParseAction(String Action)
        {
            String result = Action;
            if (Action.Contains("%"))
            {
                // Get parts from Action
                String prefix = String.Empty;
                String macro = String.Empty;
                String postfix = String.Empty;
                Boolean prefixSet = false;
                Boolean macroSet = false;
                Int32 i;
                StringBuilder sb = new StringBuilder();
                System.IO.StringReader sReader = new System.IO.StringReader(Action);
                while ((i = sReader.Read()) != -1)
                {
                    if (Convert.ToChar(i) == '%')
                    {
                        if (prefixSet == false)
                        {
                            prefix = sb.ToString();
                            sb.Clear();
                            prefixSet = true;
                        }
                        else if (macroSet == false)
                        {
                            macro = sb.ToString();
                            sb.Clear();
                            macroSet = true;
                        }
                        else
                        {
                            sb.Append(Convert.ToChar(i));
                        }
                    }
                    else
                    {
                        sb.Append(Convert.ToChar(i));
                    }
                }
                postfix = sb.ToString();
                if (macro.ToUpper() == "GUID")
                {
                    result = Guid.NewGuid().ToString();
                }
                if (macro.ToUpper().Contains("DATETIME"))
                {
                    String dateFormat = macro.Substring(
                        macro.IndexOf(":") + 1);
                    result = DateTime.Now.ToString(dateFormat);
                }
                result = prefix + result + postfix;
            }
            return result;
        }
    }
}
